package com.wiiss.framework.aspectj;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.wiiss.common.enums.ControllerFilterLogInfo;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * 基于slf4j的MDC工具实现链路追踪
 * 在日志中打印missionId
 */
@Order(0) // order数字越小的越先执行，越容易被覆盖（同心圆原则）
@Aspect
@Component
@Slf4j
public class ControllerLogAspect {
    @Autowired
    private ObjectMapper objectMapper;

    @Pointcut("execution (* com.wiiss.*.controller.*.*(..))")
    public void controllerPointcut() {
    }

    @Around("controllerPointcut()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();

        // 获取请求信息
        String url = request.getRequestURL().toString();
        String httpMethod = request.getMethod();
        String name = joinPoint.getSignature().getName();
        String params;
        try {
            params = objectMapper.writeValueAsString(joinPoint.getArgs());
            if (ControllerFilterLogInfo.filterMethod(ControllerFilterLogInfo.REQ_001.getType(), url)) {
                params = "该方法不打印请求报文";
            }
        } catch (Exception e) {
            params = "无法序列化请求参数";
        }

        // 记录请求日志
        log.info("请求开始 => URL: {}, HTTP方法: {}, 参数: {}", url, httpMethod, params);

        long startTime = System.currentTimeMillis();
        Object result;
        try {
            // 执行Controller方法
            result = joinPoint.proceed();
        } finally {
            // 计算耗时
            long costTime = System.currentTimeMillis() - startTime;
            log.info("请求结束 => URL: {}, 耗时: {}ms", url, costTime);
        }

        // 记录响应日志（敏感信息需过滤）
        String resp;
        try {
            resp = objectMapper.writeValueAsString(result);

        } catch (Exception e) {
            resp = "响应数据序列化失败";
        }
        if (ControllerFilterLogInfo.filterMethod(ControllerFilterLogInfo.RSP_001.getType(), name)) {
            resp = "该方法不打印返回报文";
        }
        log.debug("响应数据 => {}", resp);
        return result;
    }
}
